#include "Utils.h"

/// @param dest
/// @param src
void Strcpy(char *dest, const char *src)
{
    if (!dest || !src)
    {
        return;
    }

    while (*dest && *src)
    {
        *dest++ = *src++;
    }
    *dest = '\0';
}

/// @brief Copy a specified number of characters from one string to another
/// @param dest
/// @param src
/// @param size
void Strncpy(char *dest, const char *src, int size)
{
    if (!dest || !src || !size)
    {
        return;
    }

    char *d = dest;
    const char *s = src;

    while ((size-- > 0) && (*s))
    {
        *d++ = *s++;
    }
    if (size == 0)
    {
        *(d - 1) = '\0';
    }
    else
    {
        *d = '\0';
    }
}

/// @brief Get the length of a string
/// @param str
/// @return
int Strlen(const char *str)
{
    if (str == (const char *)0)
    {
        return 0;
    }

    const char *c = str;

    int len = 0;
    while (*c++)
    {
        len++;
    }

    return len;
}

/// @brief Compare specified length of two strings
/// @param s1
/// @param s2
/// @param size
/// @return
int Strncmp(const char *s1, const char *s2, int size)
{
    if (!s1 || !s2)
    {
        return -1;
    }

    while (*s1 && *s2 && (*s1 == *s2) && size)
    {
        s1++;
        s2++;
        size--;
    }

    return !((*s1 == '\0') || (*s2 == '\0') || (*s1 == *s2));
}

void Memcpy(void *dest, void *src, int size)
{
    if (!dest || !src || !size)
    {
        return;
    }

    uint8_t *s = (uint8_t *)src;
    uint8_t *d = (uint8_t *)dest;
    while (size--)
    {
        *d++ = *s++;
    }
}

void Memset(void *dest, uint8_t v, int size)
{
    if (!dest || !size)
    {
        return;
    }

    uint8_t *d = (uint8_t *)dest;
    while (size--)
    {
        *d++ = v;
    }
}

bool Memcmp(void *d1, void *d2, int size)
{
    if (!d1 || !d2)
    {
        return false;
    }

    uint8_t *p_d1 = (uint8_t *)d1;
    uint8_t *p_d2 = (uint8_t *)d2;
    while (size--)
    {
        if (*p_d1++ != *p_d2++)
        {
            return false;
        }
    }

    return true;
}

uint32_t UpAlign(uint32_t size, uint32_t bound)
{
    return (size + bound - 1) & ~(bound - 1);
}

uint32_t DownAlign(uint32_t size, uint32_t bound)
{
    return (size & ~(bound - 1));
}

void Num2Char(char *buf, int num, int base)
{
    static const char *num2ch = {"FEDCBA9876543210123456789ABCDEF"};
    char *p = buf;
    int old_num = num;

    // 仅支持部分进制
    if ((base != 2) && (base != 8) && (base != 10) && (base != 16))
    {
        *p = '\0';
        return;
    }

    // 只支持十进制负数
    int signed_num = 0;
    if ((num < 0) && (base == 10))
    {
        *p++ = '-';
        signed_num = 1;
    }

    if (signed_num)
    {
        do
        {
            char ch = num2ch[num % base + 15];
            *p++ = ch;
            num /= base;
        } while (num);
    }
    else
    {
        uint32_t u_num = (uint32_t)num;
        do
        {
            char ch = num2ch[u_num % base + 15];
            *p++ = ch;
            u_num /= base;
        } while (u_num);
    }
    *p-- = '\0';

    // 将转换结果逆序，生成最终的结果
    // 543 -> 345
    char *start = (!signed_num) ? buf : buf + 1;
    while (start < p)
    {
        char ch = *start; // 5
        *start = *p;      // 3
        *p-- = ch;        // 5
        start++;
    }
}

void StringFormat(char *buffer, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    StringFormatArgs(buffer, format, args);
    va_end(args);
}

void StringFormatArgs(char *buffer, const char *format, va_list args)
{
    enum
    {
        NORMAL,
        READ_BYTE
    } state = NORMAL;
    char *curr = buffer;
    char ch;
    while ((ch = *format++))
    {
        switch (state)
        {
            case NORMAL:
                if (ch == '%')
                    state = READ_BYTE;
                else
                    *curr++ = ch;
                break;
            case READ_BYTE:
                if (ch == 'd')
                {
                    int value = va_arg(args, int);
                    Num2Char(curr, value, 10);
                    curr += Strlen(curr);
                }
                else if (ch == 'x')
                {
                    int value = va_arg(args, int);
                    Num2Char(curr, value, 16);
                    curr += Strlen(curr);
                }
                else if (ch == 'c')
                {
                    char c = va_arg(args, int);
                    *curr++ = c;
                }
                else if (ch == 's')
                {
                    const char *str = va_arg(args, char *);
                    int len = Strlen(str);
                    while (len--)
                    {
                        *curr++ = *str++;
                    }
                }
                state = NORMAL;
                break;
        }
    }
}

int StringCount(char** start)
{
    int count = 0;
    if (start)
    {
        while (*start++)
        {
            count++;
        }
    }
    return count;
}

char* GetFileName(char* name)
{
    char * s = name;

    // 定位到结束符
    while (*s != '\0') {
        s++;
    }

    // 反向搜索，直到找到反斜杆或者到文件开头
    while ((*s != '\\') && (*s != '/') && (s >= name)) {
        s--;
    }
    return s + 1;
}

void Error(const char *file, int line, const char *func, const char *condition)
{
}